function InterceptorManager() {
    this.handlers = []
}
InterceptorManager.prototype.use = function (fulfilled, rejected) {
    this.handlers.push({
        fulfilled,
        rejected
    })
}
function Axios(config) {
    this.defaults = config;
    this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
    }
}

function CancelToken(executor){
    let resolvePromise = null;
    this.promise = new Promise((resolve,reject)=>{
        resolvePromise = resolve;
    })
    executor(()=>{
        // resolvePromise执行，就可以改变 this.promise的状态为成功。
        resolvePromise();
    })
}

Axios.prototype.request = function (config) {
    // 请求的核心方法，dispatchRequest => 是函数，返回值是 promise对象
    let dispatchRequest = (config)=>{
        return new Promise((resolve,reject)=>{
            const xhr = new XMLHttpRequest();
            xhr.open(config.method, config.url);
            xhr.responseType = 'json'
            xhr.send();
            xhr.onreadystatechange = function(){
                if(xhr.readyState !== 4) return;
                if(xhr.status >=200 && xhr.status < 300){
                    xhr.response
                    let res = {
                        request:xhr,
                        status:xhr.status,
                        statusText:xhr.statusText,
                        headers:config.headers,
                        data:xhr.response
                    }
                    resolve(res);
                }else{
                    reject(xhr.status);
                }
            }
            if(config.cancelToken){
                config.cancelToken.promise.then(()=>{
                    xhr.abort();
                })
            }
        })
    }
    // 初始化 chain
    let chain = [dispatchRequest, undefined];
    // 添加请求拦截，其实就是向chain数组前面追加元素
    this.interceptors.request.handlers.forEach(item=>{
        chain.unshift(item.fulfilled,item.rejected);
    })
    // 添加响应拦截器
    this.interceptors.response.handlers.forEach(item=>{
        chain.push(item.fulfilled,item.rejected);
    })
    // 启动链条的调用
    let promise = Promise.resolve(config);
    while(chain.length){
        promise = promise.then(chain.shift(), chain.shift())
    }
    return promise;
}
let methods = ['get', 'post', 'delete', 'put', 'patch'];
methods.forEach(method => {
    Axios.prototype[method] = () => {
        return this.request(config);
    }
})
// createInstance
function createInstance(config) {
    // 1. 使用Axios.prototype.request创造 instance
    // 2. 将 Axios.prototype原型上的方法，都加载 instance身上
    // 3. 将 new Axios() 实例对象的属性也加载 instance身上

    //创建 Axios实例对象
    const context = new Axios(config);
    // 创建instance实例
    const instance = Axios.prototype.request.bind(context);
    // 将 Axios.prototype原型上的方法，都加载 instance身上
    Object.keys(Axios.prototype).forEach(method => {
        instance[method] = Axios.prototype[method]
    })
    // 将Axios 实例对象的属性[defaults , interceptors]也加载 instance身上
    Object.keys(context).forEach(attr => {
        instance[attr] = context[attr];
    })
    return instance;
}
const axios = createInstance({ method: 'post' });
// 将Axios类添加到 axios上，成为他的一个属性
axios.Axios = Axios;
// 创建create方法。 create方法之所以可以进行多站点配置，因为它也是执行createInstance 创建的。
axios.create = function (config) {
    return createInstance(config);
}

axios.CancelToken = CancelToken;


